package com.i360day.redis.listener;

import com.i360day.redis.annotation.RedisExpireListener;
import com.i360day.redis.annotation.RedisKeyExpireListener;
import com.i360day.redis.annotation.RedisKeyListener;
import com.i360day.redis.annotation.RedisListener;
import com.i360day.redis.listener.keyexpire.RedisKeyExpireActuator;
import com.i360day.redis.listener.keyexpire.RedisKeyExpireListenerAdapter;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @program: spring-redis
 * @description:
 * @author: liju.z
 * @create: 2021-08-01 17:26
 **/
@Configuration
public class RedisListenerConfiguration {

    /**
     * <p> @Author liju.z <p>
     *
     * <p> @Description 创建redis key值过期执行器 <p>
     *
     * <p> @Date  10:43 <p>
     *
     * <p> @Param [applicationContext] <p>
     *
     * <p> @return [applicationContext] <p>
     **/
    @Bean
    public RedisKeyExpireActuator registryRedisExpire(ApplicationContext applicationContext) {
        List<RedisKeyExpireListenerAdapter> redisKeyExpireList = new ArrayList<>();
        Map<String, Object> beansOfType = applicationContext.getBeansOfType(Object.class);
        beansOfType.forEach((beanName, beanClass) -> {
            if (beanClass instanceof RedisKeyExpireListenerAdapter) {
                RedisExpireListener redisExpireListener = AnnotationUtils.findAnnotation(AopProxyUtils.ultimateTargetClass(beanClass), RedisExpireListener.class);
                if (redisExpireListener != null) {
                    redisKeyExpireList.add((RedisKeyExpireListenerAdapter) beanClass);
                }
                RedisKeyExpireListener redisKeyExpireListener = AnnotationUtils.findAnnotation(AopProxyUtils.ultimateTargetClass(beanClass), RedisKeyExpireListener.class);
                if (redisKeyExpireListener != null) {
                    redisKeyExpireList.add((RedisKeyExpireListenerAdapter) beanClass);
                }
            }
        });
        return new RedisKeyExpireActuator(redisKeyExpireList);
    }

    /**
     * <p> @Author liju.z <p>
     *
     * <p> @Description key值监听器 <p>
     *
     * <p> @Date  16:11 <p>
     *
     * <p> @Param [redisMessageListenerContainer, redisKeyExpireActuator] <p>
     *
     * <p> @return [redisMessageListenerContainer, redisKeyExpireActuator] <p>
     **/
    @Bean
    public RedisKeyExpireMessageListener redisKeyExpireMessageListener(
            RedisMessageListenerContainer redisMessageListenerContainer,
            RedisKeyExpireActuator redisKeyExpireActuator) {
        return new RedisKeyExpireMessageListener(redisMessageListenerContainer, redisKeyExpireActuator);
    }

    /**
     * <p> @Author liju.z <p>
     *
     * <p> @Description 创建消费监听器 <p>
     *
     * <p> @Date  10:27 <p>
     *
     * <p> @Param [redisProperties] <p>
     *
     * <p> @return [redisProperties] <p>
     **/
    @Bean
    @ConditionalOnMissingBean
    public RedisMessageListenerContainer messageListener(ApplicationContext applicationContext, RedisConnectionFactory factory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(factory);
        Map<String, Object> beansOfType = applicationContext.getBeansOfType(Object.class);
        beansOfType.forEach((beanName, beanClass) -> {
            if (!(beanClass instanceof MessageListener)) return;
            MessageListener messageListener = (MessageListener) beanClass;
            //使用类作为key监听
            RedisListener redisListener = AnnotationUtils.findAnnotation(AopProxyUtils.ultimateTargetClass(beanClass), RedisListener.class);
            if (redisListener != null && !redisListener.key().equals(void.class)) {
                for (Class<?> clazz : redisListener.key()) {
                    container.addMessageListener(messageListener, new PatternTopic(clazz.getName()));
                }
            }
            //使用string作为key
            RedisKeyListener redisKeyListener = AnnotationUtils.findAnnotation(AopProxyUtils.ultimateTargetClass(beanClass), RedisKeyListener.class);
            if (redisKeyListener != null && !ObjectUtils.isEmpty(redisKeyListener.key())) {
                for (String redisListenerKey : redisKeyListener.key()) {
                    container.addMessageListener(messageListener, new PatternTopic(redisListenerKey));
                }
            }
        });
        return container;
    }
}
